﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using Common.Password;

namespace EFDataModel
{
    /// <summary>
    /// Authentication von Benutzern, Einloggen, Passwort setzten, Prüfen ob der User Exisitert, ...
    /// </summary>
    public partial class EFAuthentication
    {
        #region Static
        /// <summary>
        /// Nur wenn der User gefunden wurde und das PW korrekt war, dann wird der User zurückgegeben, sonst Null
        /// </summary>
        /// <param name="userName">Username (eMail)</param>
        /// <param name="password">Passwort</param>
        /// <param name="efModelContainer">Der DataModelContainer in dem gesucht werden soll</param>
        /// <param name="errorMessage">Referenz auf den Fehlerstring für den Loginvorgang</param>
        public static EFAuthentication LoginUser(string userName, string password, EFModelContainer efModelContainer, ref string errorMessage)
        {
            //Suchen des Users mit der übergebenen Mailadresse
            var loginUser = (from eUser in efModelContainer.EFBaseMenge.OfType<EFAuthentication>() where eUser.LoginEmail == userName select eUser).FirstOrDefault();

            //Prüfen ob User gefunden wurde und das PW stimmen
            if (loginUser != null && loginUser.ID != 0)
            {
                //darf sich nur einloggen, wenn noch keine 5 Logintries durchgeführt wurden.
                if (loginUser.CheckPassword(password))
                {
                    if (loginUser.Logintries < 6)
                    {
                        //Prüfen ob es sich um einen aktiven User handelt, denn nur der darf sich auch einloggen.
                        if (loginUser.IsActiveUser)
                        {
                            //Setzten des letzten Logindatum
                            loginUser.LastLoginDate = loginUser.CurrentLoginDate;
                            loginUser.CurrentLoginDate = DateTime.Now;

                            loginUser.Logintries = 0;
                            efModelContainer.SaveChanges();
                            return loginUser;
                        }
                        else
                        {
                            //Account ist deaktiviert, und muss aktiviert werden vom Administrator
                            errorMessage = Resources.EFResources.AccountDisabledRESX;
                        }
                    }
                    else
                    {
                        //Account wurde gesperrt, da zu viele Logintries durchgeführt wurden
                        errorMessage = Resources.EFResources.TooManyLoginTriesRESX;
                    }
                }
                else
                {
                    //bei einem Fehlversuch die Logintries hochzählen
                    loginUser.Logintries++;
                    efModelContainer.SaveChanges();
                    errorMessage = Resources.EFResources.LoginnameOrPasswordWrongRESX;
                }
            }
            else
            {
                errorMessage = Resources.EFResources.LoginnameOrPasswordWrongRESX;
            }

            //Kein User gefunden oder PW falsch.
            return null;
        }

        /// <summary>
        /// Prüfen ob der übergebene Usernname bereits existiert.
        /// </summary>
        /// <param name="userName">Username der geprüft werden soll</param>
        /// <param name="efModelContainer"></param>
        /// <returns>TRUE->Existiert, FALSE->Existiert noch nicht</returns>
        public static bool CheckUserExists(string userName, EFModelContainer efModelContainer)
        {
            //Nach dem Usernamen suchen, ob dieser bereits existiert.
            var user = (from eUser in efModelContainer.EFBaseMenge.OfType<EFAuthentication>() where eUser.LoginEmail.ToLower() == userName.ToLower() select eUser.ID).FirstOrDefault();

            if (user != 0)
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Die Anzahl wie oft das PW gehasht werden soll, je öfter das PW gehast wird inkl. Salt, desto unmöglicher ist es dieses wiederherzustellen aus dem Hash
        /// </summary>
        public static int HashCount = 10;

        /// <summary>
        /// Dateformat für den PW Salt Faktor
        /// </summary>
        public static string PasswordDateFormat = "dd.MM.yyyy mm:hh";
        #endregion

        #region Public Functions
        /// <summary>
        /// Setzten des Passwortes für den User.
        /// </summary>
        /// <param name="password">Das Passwort was gesetzt werden soll</param>
        public void SetPassword(string password)
        {
            //Setzten des Passwortes für den User, inkl. Mehrfachhash
            Password = PasswordHash.GetPasswordHash(password, CreationDate.ToString(PasswordDateFormat), HashCount);
        }

        /// <summary>
        /// Prüft das übergeben Passwort, ob dieses mit dem Userpasswort, was in der DB hinterlegt ist übereinstimmt.
        /// </summary>
        /// <param name="password">Das Passwort was überprüft werden soll</param>
        /// <returns>TRUE->Passwörter stimmen überein |FALSE->Passwörter stimmen nicht überein</returns>
        public bool CheckPassword(string password)
        {
            //Den password Hash ermitteln und dann mit dem Hashwert aus der DB vergleichen. 
            string pwHash = PasswordHash.GetPasswordHash(password, CreationDate.ToString(PasswordDateFormat), HashCount);
            //Das passwort stimmt überein
            if (pwHash == Password)
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Gibt einen String zurück der Ja für Aktiv und Nein für Inaktiv zurückgibt.
        /// </summary>
        public string IsActiveUserString()
        {
            if (IsActiveUser)
            {
                //Den passenden String aus den Ressourcen laden.
                return Resources.EFResources.YesRESX;
            }

            return Resources.EFResources.NoRESX;
        }
        #endregion
    }
}
